<template>
  <v-select
    @input="search"
    v-model="syncedSelectedItem"
    v-bind="$attrs"
    v-on="$listeners"
    :items="propItems"
    :menu-props="{ 'min-width': '216px', rounded: 'lg' }"
    class="SelectAll-input"
  >
    <template v-for="(index, name) in $scopedSlots" #[name]="slotsData">
      <slot :name="name" v-bind="slotsData" />
    </template>
    <template #label>
      <span>
        {{ propScarecrow }}
      </span>
    </template>
    <template #selection="{ index }">
      <span v-if="index === 0">{{ propScarecrow }}</span>
    </template>
    <template v-slot:prepend-item>
      <v-text-field
        v-if="propShowSearch"
        v-model="searchValue"
        @input="$emit('searchInput', searchValue)"
        hide-details
        flat
        solo
        label="search keyword"
        class="white-input search-input rounded-pill mx-2"
      >
        <template #append>
          <v-icon @click="$emit('search', searchValue)">mdi-magnify</v-icon>
        </template></v-text-field
      >
      <v-list-item
        v-if="propItems.length > 0"
        @mousedown.prevent
        @click="toggleAll"
        :class="{ 'px-4': propShowSearch }"
        ripple
      >
        <v-list-item-action>
          <v-icon :color="selectedSomeItem ? '#EB9B31' : ''">
            {{ icon }}
          </v-icon>
        </v-list-item-action>
        <v-list-item-content>
          <v-list-item-title> Select All </v-list-item-title>
        </v-list-item-content>
      </v-list-item>
    </template>
    <template #item="slotsData">
      <slot name="item" v-bind="slotsData">
        <v-menu :close-on-content-click="false" rounded="lg" offset-x>
          <template v-slot:activator="{ on }">
            <v-list-item
              class="select-list-item align-center"
              @click.stop="
                toggleItem(slotsData.item, !isEverySelected(slotsData.item))
              "
            >
              <v-list-item-action>
                <v-icon
                  :color="isSomeSelected(slotsData.item) ? '#EB9B31' : ''"
                >
                  {{ getIcon(slotsData.item) }}
                </v-icon>
              </v-list-item-action>
              <v-list-item-content>
                <v-list-item-title class="text-left">
                  {{ slotsData.item.text }}
                </v-list-item-title>
              </v-list-item-content>
              <v-list-item-icon class="ma-0">
                <v-btn v-on="on" icon v-if="slotsData.item.children">
                  <v-icon>mdi-chevron-right</v-icon>
                </v-btn>
              </v-list-item-icon>
            </v-list-item>
          </template>
          <TreeSelect
            :items="slotsData.item.children"
            :selectedItem.sync="syncedSelectedItem"
          ></TreeSelect>
        </v-menu>
      </slot>
    </template>
  </v-select>
</template>
<script lang="ts">
import { Vue, Component, PropSync } from "vue-property-decorator";
import TreeSelect from "@/components/Dashboard/SelectAll/TreeSelect.vue";

interface IItem {
  id: string;
  text: string;
  children?: Array<IItem>;
}
@Component({
  components: {
    TreeSelect,
  },
  props: {
    items: {
      type: Array,
      default: () => [],
    },
    "show-search": {
      type: Boolean,
      default: false,
    },
    scarecrow: String,
    "on-icon": {
      type: String,
      default: "mdi-checkbox-marked",
    },
    "off-icon": {
      type: String,
      default: "mdi-checkbox-blank-outline",
    },
    "indeterminate-icon": {
      type: String,
      default: "mdi-minus-box",
    },
  },
})
export default class SelectAll extends Vue {
  @PropSync("selectedItem", { type: Array, default: () => [] })
  syncedSelectedItem!: Array<IItem>;

  get propShowSearch() {
    return this.$props.showSearch;
  }

  get propItems(): Array<IItem> {
    return this.$props.items;
  }

  get propScarecrow() {
    return this.$props.scarecrow;
  }

  searchValue = "";

  search() {
    console.log(this.searchValue);
  }

  // 激活时使用的图标
  get propOnIcon() {
    return this.$props.onIcon;
  }
  // 不活动时使用的图标
  get propOffIcon() {
    return this.$props.offIcon;
  }
  // 未确定图标
  get propIndeterminateIcon() {
    return this.$props.indeterminateIcon;
  }

  // 判断传入的item是否被选中,有两种情况，一种是没有children的item，一种是有children的item
  isEverySelected(item: IItem) {
    // 有children的item判断是否全部被选中
    if (item.children) {
      const allChildren = this.getAllChild(item);

      return (
        allChildren.length > 0 &&
        allChildren.every((child) => {
          return this.syncedSelectedItem.includes(child);
        })
      );
    } else {
      // 没有children的item判断是否被选中
      return this.syncedSelectedItem.includes(item);
    }
  }

  // 判断传入的item是否被选中,有两种情况，一种是没有children的item，一种是有children的item
  isSomeSelected(item: IItem) {
    // 有children的item判断是否一些被选中
    if (item.children) {
      const allChildren = this.getAllChild(item);

      return allChildren.some((child) => {
        return this.syncedSelectedItem.includes(child);
      });
    } else {
      // 没有children的item判断是否被选中
      return this.syncedSelectedItem.includes(item);
    }
  }

  // 递归获取指定节点的所有子节点
  getAllChild(item: IItem): Array<IItem> {
    const children: Array<IItem> = [];
    // 有子节点
    if (item.children) {
      item.children.forEach((child) => {
        children.push(...this.getAllChild(child));
      });
      return children;
    } else {
      // 无子节点
      return [item];
    }
  }

  // selectAll
  toggleAll() {
    this.$nextTick(() => {
      // 取消全选
      if (this.selectedAllItem) {
        this.allChildren.forEach((item) => {
          const childIndex = this.syncedSelectedItem.indexOf(item);
          childIndex >= 0 && this.syncedSelectedItem.splice(childIndex, 1);
        });
      } else {
        // 全选
        this.allChildren.forEach((item) => {
          const childIndex = this.syncedSelectedItem.indexOf(item);
          childIndex < 0 && this.syncedSelectedItem.push(item);
        });
      }
    });
  }

  get allChildren() {
    const allChildren: IItem[] = [];
    this.propItems.forEach((item) => {
      allChildren.push(...this.getAllChild(item));
    });
    return allChildren;
  }

  get selectedAllItem() {
    // every在数组长度为0的时候会返回true所以还要判断一下数组的长度是否不为0
    return (
      this.allChildren.length > 0 &&
      this.allChildren.every((child) => {
        return this.syncedSelectedItem.includes(child);
      })
    );
  }

  get selectedSomeItem() {
    return this.allChildren.some((child) => {
      return this.syncedSelectedItem.includes(child);
    });
  }

  get icon() {
    if (this.selectedAllItem) return this.propOnIcon;
    if (this.selectedSomeItem) return this.propIndeterminateIcon;
    return this.propOffIcon;
  }

  // selectItem
  toggleItem(item: IItem, isSelectAll: boolean) {
    // 有子节点
    if (item.children) {
      item.children.forEach((child) => {
        this.toggleItem(child, isSelectAll);
      });
    } else {
      // 无子节点
      const itemIndex = this.syncedSelectedItem.indexOf(item);
      // 判断当前是进行全选还是全选全选
      if (isSelectAll) {
        // 全选
        // 将没选中的节点添加进选择列表
        if (itemIndex < 0) {
          this.syncedSelectedItem.push(item);
        }
      } else {
        // 取消全选
        // 将选中的节点从选择列表中移除
        if (itemIndex >= 0) {
          this.syncedSelectedItem.splice(itemIndex, 1);
        }
      }
    }
  }

  getIcon(item: IItem) {
    if (this.isEverySelected(item)) return this.propOnIcon;
    if (this.isSomeSelected(item)) return this.propIndeterminateIcon;
    return this.propOffIcon;
  }
}
</script>
<style lang="scss" scoped>
@import "./SelectAll.scss";
</style>
